import { onMounted, onUnmounted, ref } from "vue";

const getMediaRecorder = () =>
  new Promise<MediaRecorder>((resolve, reject) => {
    if (navigator.mediaDevices.getUserMedia) {
      navigator.mediaDevices.getUserMedia({ audio: true }).then(
        (stream) => {
          resolve(new MediaRecorder(stream));
        },
        (e) => {
          console.error("授权失败", e);
          reject(new Error("授权失败"));
        },
      );
    } else {
      reject(new Error("浏览器不支持 getUserMedia"));
    }
  });

type Options = {
  onOk: (audio: Blob) => void;
  onError?: (e: ErrorEvent) => void;
};

const useAudioRecorder = ({ onOk, onError }: Options) => {
  const audioRecorder = ref<MediaRecorder | null>(null);
  const audioChunks = ref<Blob[]>([]);
  const audioStatus = ref<RecordingState>("inactive");

  const handleStart = () => {
    audioChunks.value = [];
    audioStatus.value = "recording";
  };

  const handleDataAvailable = (e: BlobEvent) => {
    audioChunks.value.push(e.data);
  };

  const handleStop = () => {
    const blob = new Blob(audioChunks.value, {
      type: "audio/ogg; codecs=opus",
    });
    audioStatus.value = "inactive";
    audioChunks.value = [];

    onOk(blob);
  };

  const handleError = (e: ErrorEvent) => {
    onError?.(e);
    audioStatus.value = "inactive";
    audioChunks.value = [];
  };

  const handlePause = () => {
    audioStatus.value = "paused";
  };

  const handleResume = () => {
    audioStatus.value = "recording";
  };

  onMounted(() => {
    getMediaRecorder()
      .then((ar) => {
        ar.onstart = handleStart;
        ar.ondataavailable = handleDataAvailable;
        ar.onstop = handleStop;
        ar.onpause = handlePause;
        ar.onresume = handleResume;
        ar.onerror = handleError;
        audioRecorder.value = ar;
      })
      .catch((err) => {
        onError?.(err);
      });
  });

  onUnmounted(() => {
    audioRecorder.value?.stop();
  });

  const start = () => {
    audioRecorder.value?.start();
  };

  const stop = () => {
    audioRecorder.value?.stop();
  };

  const pause = () => {
    audioRecorder.value?.pause();
  };

  const resume = () => {
    audioRecorder.value?.resume();
  };

  return { start, stop, pause, resume, status: audioStatus };
};

export default useAudioRecorder;
